package com.fileupload.monitor;

import com.fileupload.config.ConfigReader;
import com.fileupload.config.MonitorConfig;
import com.fileupload.thread.ThreadManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 监控管理器<br>
 * 负责管理所有的文件监控器，提供监控器的初始化、启动、停止和状态查询功能<br>
 * 该组件是文件监控系统的核心，协调配置加载、监控器创建和线程管理
 * 
 * @author 小乙
 * @version 1.0
 * @since 2024-01-01
 */
@Component
public class MonitorManager {
    /**
     * 日志记录器
     */
    private static final Logger logger = LoggerFactory.getLogger(MonitorManager.class);
    
    /**
     * 配置读取器 - 负责加载监控配置信息
     */
    @Autowired
    private ConfigReader configReader;
    
    /**
     * 文件变更监听器 - 处理文件系统事件
     */
    @Autowired
    private FileChangeListener fileChangeListener;
    
    /**
     * 线程管理器 - 负责任务调度和线程生命周期管理
     */
    @Autowired
    private ThreadManager threadManager;
    
    /**
     * 监控器缓存 - 使用监控器名称作为key，存储所有活动的监控器实例
     */
    private Map<String, FileMonitor> monitorCache = new ConcurrentHashMap<>();
    
    /**
     * 线程锁 - 保证监控器操作的线程安全，防止并发修改问题
     */
    private ReentrantLock lock = new ReentrantLock();
    
    /**
     * 初始化方法<br>
     * 在Bean初始化时自动调用，负责加载配置并创建所有监控器
     * 使用PostConstruct注解确保在依赖注入完成后执行
     */
    @PostConstruct
    public void init() {
        logger.info("[监控管理进程] 开始初始化监控管理器");
        
        // 初始化所有监控器
        logger.info("[监控管理进程] 加载所有监控配置");
        Map<String, MonitorConfig> monitorConfigs = configReader.getAllMonitorConfigs();
        logger.info("[监控管理进程] 共加载到 {} 个监控配置", monitorConfigs.size());
        
        for (Map.Entry<String, MonitorConfig> entry : monitorConfigs.entrySet()) {
            String monitorName = entry.getKey();
            MonitorConfig config = entry.getValue();
            
            logger.info("[监控管理进程] 开始初始化监控器: {}, 监控目录: {}", monitorName, config.getMonitorDir());
            try {
                // 创建并启动监控器
                logger.info("[监控管理进程] 创建监控器实例: {}", monitorName);
                FileMonitor monitor = createMonitor(config);
                if (monitor != null) {
                    lock.lock();
                    try {
                        monitorCache.put(monitorName, monitor);
                        logger.info("[监控管理进程] 监控器实例已缓存: {}", monitorName);
                    } finally {
                        lock.unlock();
                    }
                    
                    logger.info("[监控管理进程] 监控器[{}]初始化完成", monitorName);
                }
            } catch (Exception e) {
                logger.error("[监控管理进程] 初始化监控器[{}]失败: {}, 异常: {}", monitorName, e.getMessage(), e);
            }
        }
        
        // 启动所有监控器
        logger.info("[监控管理进程] 启动所有监控器");
        startAllMonitors();
        
        logger.info("[监控管理进程] 监控管理器初始化完成，共初始化 {} 个监控器", monitorCache.size());
    }
    
    /**
     * 销毁方法<br>
     * 在Bean销毁时自动调用，负责停止所有监控器并清理资源
     * 使用PreDestroy注解确保在应用关闭前执行
     */
    @PreDestroy
    public void destroy() {
        logger.info("开始关闭监控管理器");
        
        // 停止所有监控器
        stopAllMonitors();
        
        // 清空监控器缓存
        lock.lock();
        try {
            monitorCache.clear();
        } finally {
            lock.unlock();
        }
        
        logger.info("监控管理器已关闭");
    }
    
    /**
     * 创建监控器<br>
     * 根据监控配置创建相应的文件监控器实例
     * 
     * @param config 监控配置信息
     * @return 创建的文件监控器实例，如果创建失败返回null
     */
    private FileMonitor createMonitor(MonitorConfig config) {
        try {
            String dirPath = config.getMonitorDir();
            logger.info("[监控管理进程] 验证监控目录: {}", dirPath);
            File dir = new File(dirPath);
            if (!dir.exists() || !dir.isDirectory()) {
                logger.error("[监控管理进程] 监控目录不存在或不是有效目录: {}", dirPath);
                return null;
            }
            
            logger.info("[监控管理进程] 创建NIO文件监控器实例: {}, 监控目录: {}", config.getName(), dirPath);
            FileMonitor monitor = new NioFileMonitor(config, fileChangeListener);
            logger.info("[监控管理进程] 创建监控器成功: {}, 监控后缀: {}", config.getName(), config.getMonitorFileSuffix());
            return monitor;
        } catch (Exception e) {
            logger.error("[监控管理进程] 创建监控器失败: {}, 异常: {}", e.getMessage(), e);
            return null;
        }
    }
    
    /**
     * 启动所有监控器<br>
     * 遍历所有监控器实例并启动它们，使用线程锁确保线程安全
     */
    public void startAllMonitors() {
        lock.lock();
        try {
            logger.info("[监控管理进程] 开始启动所有监控器，共 {} 个", monitorCache.size());
            for (Map.Entry<String, FileMonitor> entry : monitorCache.entrySet()) {
                String monitorName = entry.getKey();
                FileMonitor monitor = entry.getValue();
                
                logger.info("[监控管理进程] 启动监控器: {}", monitorName);
                try {
                    // 使用线程管理器启动监控线程
                    threadManager.submitTask("monitor-" + monitorName, () -> {
                        try {
                            monitor.start();
                        } catch (Exception e) {
                            logger.error("[监控管理进程] 监控器 [{}] 启动异常: {}, 异常: {}", monitorName, e.getMessage(), e);
                        }
                    });
                    logger.info("[监控管理进程] 监控器[{}]启动成功", monitorName);
                } catch (Exception e) {
                    logger.error("[监控管理进程] 启动监控器[{}]失败: {}, 异常: {}", monitorName, e.getMessage(), e);
                }
            }
            logger.info("[监控管理进程] 所有监控器启动完成");
        } finally {
            lock.unlock();
        }
    }
    
    /**
     * 停止所有监控器<br>
     * 遍历所有监控器实例并停止它们，使用线程锁确保线程安全
     */
    public void stopAllMonitors() {
        lock.lock();
        try {
            for (Map.Entry<String, FileMonitor> entry : monitorCache.entrySet()) {
                String monitorName = entry.getKey();
                FileMonitor monitor = entry.getValue();
                
                try {
                    // 先取消线程
                    threadManager.cancelTask("monitor-" + monitorName, true);
                    // 再停止监控器
                    monitor.stop();
                    logger.info("停止监控器: {}", monitorName);
                } catch (Exception e) {
                    logger.error("停止监控器[{}]失败: {}", monitorName, e.getMessage());
                }
            }
        } finally {
            lock.unlock();
        }
    }
    
    /**
     * 启动指定的监控器<br>
     * 根据监控器名称启动对应的监控器实例
     * 
     * @param monitorName 监控器名称
     * @return 是否成功启动监控器
     */
    public boolean startMonitor(String monitorName) {
        lock.lock();
        try {
            FileMonitor monitor = monitorCache.get(monitorName);
            if (monitor != null) {
                try {
                    monitor.start();
                    logger.info("启动监控器: {}", monitorName);
                    return true;
                } catch (Exception e) {
                    logger.error("启动监控器[{}]失败: {}", monitorName, e.getMessage());
                }
            } else {
                logger.error("监控器不存在: {}", monitorName);
            }
            return false;
        } finally {
            lock.unlock();
        }
    }
    
    /**
     * 停止指定的监控器<br>
     * 根据监控器名称停止对应的监控器实例
     * 
     * @param monitorName 监控器名称
     * @return 是否成功停止监控器
     */
    public boolean stopMonitor(String monitorName) {
        lock.lock();
        try {
            FileMonitor monitor = monitorCache.get(monitorName);
            if (monitor != null) {
                try {
                    // 先取消线程
                    threadManager.cancelTask("monitor-" + monitorName, true);
                    // 再停止监控器
                    monitor.stop();
                    logger.info("停止监控器: {}", monitorName);
                    return true;
                } catch (Exception e) {
                    logger.error("停止监控器[{}]失败: {}", monitorName, e.getMessage());
                }
            } else {
                logger.error("监控器不存在: {}", monitorName);
            }
            return false;
        } finally {
            lock.unlock();
        }
    }
    
    /**
     * 获取所有监控器的状态<br>
     * 返回每个监控器的运行状态映射
     * 
     * @return 监控器名称到运行状态的映射
     */
    public Map<String, Boolean> getAllMonitorStatus() {
        Map<String, Boolean> statusMap = new HashMap<>();
        
        lock.lock();
        try {
            for (Map.Entry<String, FileMonitor> entry : monitorCache.entrySet()) {
                String monitorName = entry.getKey();
                FileMonitor monitor = entry.getValue();
                statusMap.put(monitorName, monitor.isRunning());
            }
        } finally {
            lock.unlock();
        }
        
        return statusMap;
    }
    
    /**
     * 获取指定监控器<br>
     * 根据监控器名称获取对应的监控器实例
     * 
     * @param monitorName 监控器名称
     * @return 监控器实例，如果不存在返回null
     */
    public FileMonitor getMonitor(String monitorName) {
        lock.lock();
        try {
            return monitorCache.get(monitorName);
        } finally {
            lock.unlock();
        }
    }
    
    /**
     * 刷新监控器<br>
     * 重新创建并启动指定的监控器，用于配置更新后刷新监控逻辑
     * 
     * @param monitorName 监控器名称
     * @return 是否成功刷新监控器
     */
    public boolean refreshMonitor(String monitorName) {
        lock.lock();
        try {
            // 获取现有监控器并停止
            FileMonitor oldMonitor = monitorCache.get(monitorName);
            if (oldMonitor != null) {
                try {
                    oldMonitor.stop();
                } catch (Exception e) {
                    logger.error("停止旧监控器失败: {}", e.getMessage());
                }
            }
            
            // 获取监控配置
            MonitorConfig config = configReader.getMonitorConfig(monitorName);
            if (config == null) {
                logger.error("监控配置不存在: {}", monitorName);
                return false;
            }
            
            // 创建新监控器
            FileMonitor newMonitor = createMonitor(config);
            if (newMonitor != null) {
                // 替换监控器缓存
                monitorCache.put(monitorName, newMonitor);
                
                // 启动新监控器
                try {
                    // 使用线程管理器启动监控线程
                    threadManager.submitTask("monitor-" + monitorName, () -> {
                        try {
                            newMonitor.start();
                        } catch (Exception e) {
                            logger.error("监控器 [{}] 启动异常: {}", monitorName, e.getMessage(), e);
                        }
                    });
                    logger.info("监控器[{}]刷新成功", monitorName);
                    return true;
                } catch (Exception e) {
                    logger.error("启动新监控器失败: {}", e.getMessage());
                }
            }
            
            return false;
        } finally {
            lock.unlock();
        }
    }
    
    /**
     * 获取监控器数量<br>
     * 返回当前管理的监控器总数
     * 
     * @return 监控器数量
     */
    public int getMonitorCount() {
        lock.lock();
        try {
            return monitorCache.size();
        } finally {
            lock.unlock();
        }
    }
}